from sqlalchemy import *
from operator import *
from math import floor
from db import *
import re


class qWord(object):
	def __init__(self,word,n):
		self.word = word
		self.n = n
	def __repr__(self):
		return self.word
	def __return__(self,return_type):
		if return_type==None:
			return_type="w"
		if return_type == "s":
			return self.aye.sure
		if return_type == "a":
			return self.aye
		if return_type == "w":
			return self
	def prev(self):
		if self.n==1:
			return self.aye.prev().words[-1]
		else:
			return self.aye.words[self.n-2]
	def next(self):
		if self.n==len(self.aye.words):
			return self.aye.next().words[0]
		else:
			return self.aye.words[self.n]


class qAye(object):
	def __init__(self,n):
		self.n = n
	def __repr__(self):
		return self.data.data
	def __return__(self,return_type):
		if return_type==None:
			return_type="a"
		if return_type == "s":
			return self.sure
		if return_type == "a":
			return self
		if return_type == "w":
			return self.words

	def prev(self):
		if self.n==1:
			return self.sure.prev().ayat[-1]
		else:
			return self.sure.ayat[self.n-2]
	def next(self):
		if self.n==len(self.sure.ayat):
			return self.sure.next().ayat[0]
		else:
			return self.sure.ayat[self.n]

class _qAyeData(object):
	pass
class _qAyeDataNoErab(object):
	pass

class qSure(object):
	def __repr__(self):
		i = 1
		s = ""
		for a in self.ayat:
			s = s + "%s(%d)" % (a.__repr__(),i)
			i = i + 1
		return s
	def __return__(self,return_type):
		if return_type==None:
			return_type="s"
		if return_type == "s":
			return self
		if return_type == "a":
			return self.ayat
		if return_type == "w":
			words = []
			for a in self.ayat:
				words = words + a.words
	
	def prev(self):
		return sure_query.get(self.id-1)
	def next(self):
		return sure_query.get(self.id+1)

sure_table = Table('sure_table',metadata,
		Column('id',Integer,primary_key=True),
		Column('name',String(255)))


aye_table = Table('aye_table',metadata,
		Column('id',Integer,primary_key=True),
		Column('sure_id',Integer,ForeignKey("sure_table.id")),
		Column('n',Integer))
_aye_data_table = Table('aye_data_table',metadata,
		Column('aye_id',Integer,ForeignKey("aye_table.id"),primary_key=True),
		Column('data',String))
_aye_data_no_erab_table = Table('aye_data_no_erab_table',metadata,
		Column('aye_id',Integer,ForeignKey("aye_table.id"),primary_key=True),
		Column('data',String))


word_table = Table('word_table',metadata,
		Column('id',Integer,primary_key=True),
		Column('aye_id',Integer,ForeignKey("aye_table.id")),
		Column('n',Integer),
		Column('word',String),
		Column('noErabWord',String))



word_mapper = mapper(qWord,word_table,order_by=[word_table.c.aye_id,word_table.c.n])
aye_mapper = mapper(qAye,aye_table,order_by=[aye_table.c.sure_id,aye_table.c.n],properties = {'words' : relation(qWord,backref='aye')})
_aye_data_mapper = mapper(_qAyeData,_aye_data_table,properties = { 'aye' : relation(qAye,backref=backref('data',uselist=False))})
_aye_data_no_erab_mapper = mapper(_qAyeDataNoErab,_aye_data_no_erab_table,properties = { 'aye' : relation(qAye,backref=backref('noErabData',uselist=False))})
sure_mapper = mapper(qSure,sure_table,order_by=[sure_table.c.id],properties = {	'ayat' : relation(qAye,backref='sure')})

word_query = session.query(qWord)
aye_query = session.query(qAye)
_aye_data_query = session.query(_qAyeData)
_aye_data_no_erab = session.query(_qAyeData)
sure_query = session.query(qSure)



server_isSupports = []
server_isStartSupports = []
server_filter = []
server_start_filter = []

def filter(query,domain=None):
	if domain==None:
		domain = get("s:*/")

	i = 0
	for server in server_isSupports:
		if server(query,domain):
			return server_filter[i](query,domain)
		i = i + 1
	return domain	

def isAyeInQPath(aye,sureQ,ayeQ):
	sureOK = False
	if not sureOK and sureQ.isdigit() and aye.sure.id==int(sureQ):
		sureOK = True
	if not sureOK :
		y = re.compile("^([0-9]+)\-([0-9]+)$")
		r1 = y.search(sureQ)
		if r1!=None:
			if aye.sure.id >= r1.group(1) and aye.sure.id <= r1.group(2) :
				sureOK = True
		else:
			sures = sure_query.select(qSure.c.name.like(sureQ))
			if aye.sure in sures:
				sureOK = True
	if sureOK:
		if ayeQ=="*" or ayeQ=="%" or ayeQ=="":
			return True
		if ayeQ.isdigit():
			if aye.n == int(ayeQ):
				return True
		else:
			y = re.compile("^([0-9]+)\-([0-9]+)$")
			r1 = y.search(ayeQ)
			if r1 != None:
				if aye.n >= r1.group(1) and aye.n <= r1.group(2) :
					return True
			else:
				if ayeQ.startswith("N"):
					n = ayeQ.lstrip("N")
					if re.search(n,aye.noErabData.data):
						return True
				else:
					if re.search(ayeQ,aye.data):
						return True
					

	return False

def isWordInQPath(word,sureQ,ayeQ):
	sureOK = False
	if not sureOK and sureQ.isdigit() and word.aye.sure.id==int(sureQ):
		sureOK = True
	if not sureOK :
		y = re.compile("^([0-9]+)\-([0-9]+)$")
		r1 = y.search(sureQ)
		if r1!=None:
			if word.aye.sure.id >= r1.group(1) and word.aye.sure.id <= r1.group(2) :
				sureOK = True
		else:
			sures = sure_query.select(qSure.c.name.like(sureQ))
			if word.aye.sure in sures:
				sureOK = True
	if sureOK:
		if ayeQ=="*" or ayeQ=="%" or ayeQ=="":
			return True
		if ayeQ.isdigit():
			if word.aye.n == int(ayeQ):
				return True
		else:
			y = re.compile("^([0-9]+)\-([0-9]+)$")
			r1 = y.search(ayeQ)
			if r1 != None:
				if word.aye.n >= r1.group(1) and word.aye.n <= r1.group(2) :
					return True
			else:
				if ayeQ.startswith("N"):
					n = ayeQ.lstrip("N")
					if re.search(n,word.aye.noErabData.data):
						return True
				else:
					if re.search(ayeQ,word.aye.data):
						return True
					

	return False


def get(query):
	def __return__(fo,return_type):
		if type(fo) is type([]):
			fr = []
			for foo in fo:
				fr.append(foo.__return__(return_type))
			return fr
		else:
			return fo.__return__(return_type)

	"""
	this is main function of getting result from main engine and another servers
	example queries:
		each query cat start with w: or a: or s: which means word,aye,sure
		if there is no : the it will choose smart
		2/				# second sure of quran
		5-10/				# sures 5,6,7,8,9,10
		ب*ه/				# sures wich names starts with ب and ends with ه like بقره and بينه
		حمد/				# sure which name is حمد
		2/2				# second aye of second sure
		بقره/10-15			# ayat 10 to 15 of second sure
		100-104/1-2			# 2 first ayat of sure 100 to 104
		*/1				# all first ayat of sures
		1-10/*سَلامٌ*			# ayat from ten first sures which has word سَلامٌ
		1-10/N*سلام*			# same as above but with any erab on word
	"""
	query = query.replace("*","%")

	r = re.compile("^([was]):([^$]*)$").search(query)
	if r!=None:
		return_type = r.group(1)
		query = r.group(2)
	else:
		return_type = None;

	y = re.compile("^([0-9]+)\-([0-9]+)$")

	z = re.compile("^([^/]+)/$")
	r = z.search(query)
	if r != None:
		if r.group(1).isdigit():
			return __return__(sure_query.select(qSure.c.id==r.group(1))[0].__return__(return_type),return_type)
		else:
			r1 = y.search(r.group(1))
			if r1!=None:
				return __return__(sure_query.select(and_(qSure.c.id >= r1.group(1),qSure.c.id <= r1.group(2))),return_type)
			else:
				return __return__(sure_query.select(qSure.c.name.like(r.group(1))),return_type)

	x = re.compile("^([^/]+)/([^/]+)/?([^$]*)$")
	r = x.search(query)
	

	if r != None:
		ayat=[]

		i=0
		filtered = False
		for server in server_isStartSupports:
			if (r.group(3) != ""):
				fs = [ x+'}' for x in r.group(3).split('}')]
				if len(fs)>0  and len(fs[0])>0:
					if  (server(fs[0])):
						ayat = server_start_filter[i](r.group(1),r.group(2),fs[0])
						filtered = True
						break;
			i += 1
	
		else:
			if r.group(1).isdigit():
				sures = sure_query.select(qSure.c.id==r.group(1))
			else:
				r1 = y.search(r.group(1))
				if r1!=None:
					sures = sure_query.select(and_(qSure.c.id >= r1.group(1),qSure.c.id <= r1.group(2)))
				else:
					sures = sure_query.select(qSure.c.name.like(r.group(1)))	
			for sure in sures:
				if r.group(2).isdigit():
						ayat = ayat + __return__(aye_query.select(and_(qAye.c.sure_id==sure.id,qAye.c.n==r.group(2))),return_type)
				else:
					r1 = y.search(r.group(2))
					if r1 != None:
						ayat = ayat + __return__(aye_query.select((qAye.c.n >= r1.group(1)) & (qAye.c.n <= r1.group(2)) & (qAye.c.sure_id==sure.id)),return_type)
					else:
						if r.group(2).startswith("N"):
							n = r.group(2).lstrip("N")
							foo = aye_query.select(and_(qAye.c.id==_qAyeDataNoErab.c.aye_id,qAye.c.sure_id==sure.id) & (_qAyeDataNoErab.c.data.like(n)))
							if return_type=="w":
								fee=[]
								for f in foo:
									m = n.replace(" ","")
									fee = fee + word_query.select(and_(qWord.c.aye_id==f.id,qWord.c.noErabWord.like(m)))
								ayat = ayat + fee	
							else:
								ayat = ayat + __return__(foo,return_type)
						else:
							foo = aye_query.select(and_(qAye.c.id==_qAyeData.c.aye_id,qAye.c.sure_id==sure.id) & (_qAyeData.c.data.like(r.group(2))))
							if return_type=="w":
								fee=[]
								m = r.group(2).replace(" ","")
								for f in foo:
									fee = fee + word_query.select(and_(qWord.c.aye_id==f.id,qWord.c.word.like(m)))
								ayat = ayat + fee	
							ayat = ayat + __return__(foo,return_type)
			
		if r.group(3) != "":
			fs = [ x+'}' for x in r.group(3).split('}')]
			if filtered:
				filter_queries = fs[1:]
			else:
				filter_queries = fs
			for q in filter_queries:
				ayat = filter(q,ayat)
		return ayat



if __name__ == "__main__":
	s = sure_query.get(1)
	print s.name
	for aye in s.ayat:
		print aye
	print "-------testing query---------"
	for a in get("1/1-1000")+get("ب*ه/2") +get("110-114/1"):
		print "%s,%d:%s" % (a.sure.name,a.n,a.__repr__())
	print "-------getting various types-------"
	print get("w:*/N*القدر*")

	
